package com.act.demo.acitivitim4.service;

import com.act.demo.acitivitim4.enums.TaskEnum;
import com.act.demo.acitivitim4.taskhandler.CompleteReviewTaskHandler;
import lombok.extern.slf4j.Slf4j;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.runtime.api.query.impl.PageImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: liujin
 * @create: 2020-07-06 15:01
 */
@Slf4j
@Service
@Transactional
public class WorkFlowService {

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private TaskService taskService;

    @Resource
    private HistoryService historyService;

    @Resource
    private List<CompleteReviewTaskHandler> handlerList;

    /**
     * 开启流程
     *@param: [processDefinitionKey 流程定义KEY, businessKey businessKey, variables 流程变量]
     *@author: liujin
     *@date: 2020/6/18
     */
    public String startProcess(@NotEmpty String processDefinitionKey, @NotEmpty String businessKey, @NotEmpty String userId ,Map<String, Object> variables) {
        log.info("开启流程: processDefinitionKey {}， businessKey {}， userId {}", processDefinitionKey, businessKey, userId);
        variables.put("businessKey", businessKey);
        variables.put("user", userId);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
        String processInstanceId = processInstance.getId();
        log.info("processInstanceId = {}", processInstanceId);
        return processInstanceId;
    }

    /**
     * 完成任务 （非审核节点）
     *@param: [processInstanceId 流程实例ID, taskEnum 任务节点, variables 本地变量]
     *@author: liujin
     *@date: 2020/6/18
     */
    public void completeTask(@NotEmpty String processInstanceId, @NotNull TaskEnum taskEnum, Map<String, Object> variables) {
        log.info("完成任务：taskName {}, processInstanceId {}", taskEnum.getTaskName(), processInstanceId);
        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        Assert.notNull(task, "根据流程实例ID未找到正在运行的任务");
        taskService.complete(task.getId(), variables);
    }

    /**
     * 完成审核任务
     *@param: [processInstanceId 流程实例ID, taskEnum 任务节点, passFlag 审核是否通过, comment 备注, variables 本地变量]
     *@author: liujin
     *@date: 2020/6/18
     */
    public void completeReviewTask(@NotEmpty String processInstanceId, @NotNull TaskEnum taskEnum, boolean passFlag, @NotNull String userId ,String comment, Map<String, Object> variables) {
        log.info("完成审核任务：taskName {}, processInstanceId {}", taskEnum.getTaskName(), processInstanceId);
        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).taskDefinitionKey(taskEnum.getTaskKey()).singleResult();
        Assert.notNull(task, "根据流程实例ID未找到正在运行的任务");
        if (StringUtils.isNotEmpty(comment)) {
            //当前评论操作人信息
            Authentication.setAuthenticatedUserId(userId);
            taskService.addComment(task.getId(), task.getProcessInstanceId(), comment);
        }
        taskService.setVariableLocal(task.getId(), "passFlag", passFlag);
        taskService.complete(task.getId(), variables);

        doBusiness(processInstanceId, taskEnum, passFlag, comment, variables);
    }

    /**
     * 审核节点完成后处理业务
     *@param: [processInstanceId 流程实例ID, taskEnum 任务节点, passFlag 审核是否通过, comment 备注, variables 本地变量]
     *@author: liujin
     *@date: 2020/6/18
     */
    private void doBusiness(String processInstanceId, TaskEnum taskEnum, boolean passFlag, String comment, Map<String, Object> variables) {
        List<CompleteReviewTaskHandler> taskHandlers = handlerList.stream().filter(handler -> Objects.equals(handler.getTaskEnum(), taskEnum)).collect(Collectors.toList());
        for (CompleteReviewTaskHandler taskHandler : taskHandlers) {
            taskHandler.handler(processInstanceId, taskEnum, passFlag, comment, variables);
        }
    }

    /**
     * 个人代办任务分页
     *@param: [assignee 代办处理人, taskEnum 任务节点, businessKey businessKey, startTime, endTime, pageRequest]
     *@author: liujin
     *@date: 2020/6/18
     */
    public PageImpl assigneePage(String assignee, TaskEnum taskEnum, String businessKey , Date startTime, Date endTime, @NotNull Pageable pageRequest) {
        TaskQuery taskQuery = taskService.createTaskQuery().active().orderByTaskCreateTime().desc();
        if (StringUtils.isNotEmpty(assignee)) {
            taskQuery.taskAssignee(assignee);
        }
        return baseMyTaskQuery(taskEnum, businessKey, startTime, endTime, pageRequest, taskQuery);
    }

    /**
     * 主任务分页
     *@param: [roleCode 用户角色, taskEnum 任务节点, businessKey, startTime, endTime, pageRequest]
     *@author: liujin
     *@date: 2020/6/18
     */
    public PageImpl candidatePage(String roleCode, TaskEnum taskEnum, String businessKey ,Date startTime, Date endTime, @NotNull Pageable pageRequest) {
        TaskQuery taskQuery = taskService.createTaskQuery().orderByTaskCreateTime().desc();
        if (StringUtils.isNotEmpty(roleCode)) {
            taskQuery.taskCandidateGroup(roleCode);
        }
        return baseMyTaskQuery(taskEnum, businessKey, startTime, endTime, pageRequest, taskQuery);
    }

    /**
     * 查询任务组装分页
     *@param: [taskEnum, businessKey, startTime, endTime, pageRequest, taskQuery]
     *@author: liujin
     *@date: 2020/6/18
     */
    private PageImpl<Task> baseMyTaskQuery(TaskEnum taskEnum, String businessKey, Date startTime, Date endTime, @NotNull Pageable pageRequest, TaskQuery taskQuery) {
        if (taskEnum != null) {
            taskQuery.taskDefinitionKey(taskEnum.getTaskKey());
        }
        if (StringUtils.isNotEmpty(businessKey)) {
            taskQuery.processInstanceBusinessKey(businessKey);
        }
        if (startTime != null) {
            taskQuery.taskCreatedAfter(startTime);
        }
        if (endTime != null) {
            taskQuery.taskCreatedBefore(endTime);
        }
        long count = taskQuery.count();
        List<Task> tasks = taskQuery.listPage(pageRequest.getStartIndex(), pageRequest.getMaxItems());


        return new PageImpl<Task>(tasks, (int) count);
    }

    /**
     * 拾取任务
     *@param: [taskId 任务ID, userId 用户ID]
     *@author: liujin
     *@date: 2020/6/18
     */
    public void claim(String taskId, String userId) {
        taskService.claim(taskId, userId);
    }

    /**
     * 个人任务返回组任务
     *@param: [taskId 任务ID]
     *@author: liujin
     *@date: 2020/6/18
     */
    public void unClaim(String taskId) {
        taskService.unclaim(taskId);
    }

    /**
     * 查询已办
     *@param: [assignee 办理人, taskEnum 任务节点, businessKey, startTime, endTime, pageRequest]
     *@author: liujin
     *@date: 2020/6/18
     */
    public PageImpl<HistoricTaskInstance> historyTaskPage(String assignee, TaskEnum taskEnum, String businessKey ,Date startTime, Date endTime, @NotNull Pageable pageRequest) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery().orderByTaskCreateTime().desc();
        if (StringUtils.isNotEmpty(assignee)) {
            historicTaskInstanceQuery.taskAssignee(assignee);
        }
        if (taskEnum != null) {
            historicTaskInstanceQuery.taskDefinitionKey(taskEnum.getTaskKey());
        }
        if (StringUtils.isNotEmpty(businessKey)) {
            historicTaskInstanceQuery.processInstanceBusinessKey(businessKey);
        }
        if (startTime != null) {
            historicTaskInstanceQuery.taskCreatedAfter(startTime);
        }
        if (endTime != null) {
            historicTaskInstanceQuery.taskCreatedBefore(endTime);
        }
        long count = historicTaskInstanceQuery.count();
        List<HistoricTaskInstance> tasks = historicTaskInstanceQuery.listPage(pageRequest.getStartIndex(), pageRequest.getMaxItems());


        return new PageImpl<HistoricTaskInstance>(tasks, (int) count);
    }
}
